﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using GalaSoft.MvvmLight.Messaging;
using RSSFeedReader.Resources;
using RSSFeedReader.Services;
using RSSFeedReader.ViewModels;

namespace RSSFeedReader.Controls
{
    /// <summary>
    /// Custom TreeView class that inheritrs from <see cref="System.Windows.Controls.TreeView"/>
    /// </summary>
    public class MyTreeView : TreeView
    {
        #region Members
        Point _startPoint;
        bool _IsDragging;
        #endregion

        #region Constructor
        /// <summary>
        /// Initialise a new instance of the <see cref="RSSFeedReader.Controls.MyTreeView"/> class.
        /// </summary>
        public MyTreeView()
        {
            Initialise();
        }
        #endregion

        #region Private Methods
        private void Initialise()
        {
            PreviewMouseLeftButtonDown += OnPreviewMouseLeftButtonDown;
            MouseMove += OnMouseMove;
            DragOver += OnDragOver;
            Drop += OnDrop;
            PreviewMouseLeftButtonUp += MyTreeView_PreviewMouseLeftButtonUp;
        }

        private void MyTreeView_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _IsDragging = false;
        }

        private void OnDragOver(object sender, DragEventArgs e)
        {
            e.Effects = e.Data.GetDataPresent(typeof(ChannelViewModel)) ? DragDropEffects.Move : DragDropEffects.None;
        }

        private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _startPoint = e.GetPosition(null);
        }

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && !_IsDragging)
            {
                Point position = e.GetPosition(null);
                if ((Math.Abs(position.X - _startPoint.X) >
                        SystemParameters.MinimumHorizontalDragDistance ||
                    Math.Abs(position.Y - _startPoint.Y) >
                        SystemParameters.MinimumVerticalDragDistance) &&
                    GetItemAtLocation(_startPoint) is ChannelViewModel)
                {
                    StartDrag(e);
                }
            }
        }

        private void StartDrag(MouseEventArgs e)
        {
            _IsDragging = true;
            ChannelViewModel treeViewItemtoDrag = SelectedItem as ChannelViewModel;

            try
            {
                if (treeViewItemtoDrag == null)
                {
                    e.Handled = true;
                }
                else
                {
                    DataObject data;
                    data = new DataObject("tree", treeViewItemtoDrag);
                    DragDropEffects dde = DragDropEffects.Move;
                    if (e.RightButton == MouseButtonState.Pressed)
                    {
                        dde = DragDropEffects.All;
                    }
                    DragDrop.DoDragDrop(this, data, dde);
                }
            }
            catch (Exception ex)
            {
                ILoggerService service = Application.Current as ILoggerService;
                if (service != null)
                    service.LogMessage(Strings.LogTypeInformation, ex.Message);
                _IsDragging = false;
            }
        }

        private void OnDrop(object sender, DragEventArgs e)
        {
            try
            {
                if (e.Data.GetData("tree").GetType() == typeof(ChannelViewModel))
                {
                    ChannelViewModel fromTreeViewItem = (ChannelViewModel)e.Data.GetData("tree");
                    object toTreeViewItem = GetItemAtLocation(e.GetPosition(this));

                    if (toTreeViewItem != null)
                    {
                        //DragDropComplete(this, new MyTreeViewDragEventArgs(fromTreeViewItem, toTreeViewItem));
                        Messenger.Default.Send(new MyTreeViewDragEventArgs(fromTreeViewItem, toTreeViewItem), MainViewModel.ChannelDragDropCompleted);
                    }
                }
            }
            catch (Exception ex)
            {
                ILoggerService service = Application.Current as ILoggerService;
                if (service != null)
                    service.LogMessage(Strings.LogTypeInformation, ex.Message);
            }
            finally
            {
                _IsDragging = false;
            }
        }

        private object GetItemAtLocation(Point point)
        {
            object foundItem = null;
            HitTestResult hitTestResults = VisualTreeHelper.HitTest(this, point);

            if (hitTestResults == null)
            {
                return null;
            }

            if (hitTestResults.VisualHit is FrameworkElement)
            {
                object dataObject = (hitTestResults.VisualHit as
                    FrameworkElement).DataContext;

                if (dataObject is ChannelViewModel)
                {
                    foundItem = dataObject;
                }
                else
                {
                    foundItem = dataObject;
                }
            }
            return foundItem;
        }

        //private static T FindAnchestor<T>(DependencyObject current)
        //    where T : DependencyObject
        //{
        //    do
        //    {
        //        if (current is T)
        //        {
        //            return (T)current;
        //        }
        //        current = VisualTreeHelper.GetParent(current);
        //    }
        //    while (current != null);
        //    return null;
        //}
        #endregion
    }

    /// <summary>
    /// Provides data for drag drop event.
    /// </summary>
    public class MyTreeViewDragEventArgs : RoutedEventArgs
    {
        #region Public Properties
        /// <summary>
        /// Gets the <see cref="RSSFeedReader.ViewModels.ChannelViewModel"/> being dragged.
        /// </summary>
        public new ChannelViewModel Source { get; private set; }

        /// <summary>
        /// Gets the destination of the <see cref="RSSFeedReader.ViewModels.ChannelViewModel"/> being dragged.
        /// </summary>
        public object Destination { get; private set; }

        #endregion

        #region Constructor
        /// <summary>
        /// Initialise a new instance of the <see cref="RSSFeedReader.Controls.MyTreeViewDragEventArgs"/> class.
        /// </summary>
        /// <param name="source">The <see cref="RSSFeedReader.ViewModels.ChannelViewModel"/> being dragged.</param>
        /// <param name="destination">The destination of the <see cref="RSSFeedReader.ViewModels.ChannelViewModel"/> being dragged.</param>
        public MyTreeViewDragEventArgs(ChannelViewModel source, object destination)
        {
            Source = source;
            Destination = destination;
        }
        #endregion
    }
}
